package jpaperwork.meta.transformer.path;

import jpaperwork.meta.descriptor.Field;
import jpaperwork.meta.descriptor.Aggregation;
import jpaperwork.meta.descriptor.Polymorphism;
import jpaperwork.meta.descriptor.DiscriminatedType;

import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

import org.apache.commons.collections15.CollectionUtils;
import org.apache.commons.collections15.Transformer;
import org.apache.commons.lang.StringUtils;

public class Path {
    private List<PathElement> elements;

    public Path() {
        this.elements = new ArrayList<PathElement>();
    }

    public Path(Path path, PathElement last){
        this.elements = new ArrayList<PathElement>(path.elements.size() + 1);
        elements.addAll(path.elements);
        elements.add(last);
    }

    public List<PathElement> getElements() {
        return Collections.unmodifiableList(elements);
    }

    public Path field(Field field){
        return new Path(this, new FieldPath(field));
    }

    public Path aggregation(Aggregation aggregation, int index){
        return new Path(this, new AggregationPath(aggregation, index));
    }

    public Path polymorphic(Polymorphism polymorphism, DiscriminatedType actualType){
        return new Path(this, new PolymorhicPath(polymorphism, actualType));
    }


    public String toString(){
        return
           toHtmlName();
    }


    public String toHtmlName(){
        StringBuffer returnValue = new StringBuffer();
        int index = 0;
        for (final PathElement pathElement : elements) {
            final int index1 = index;
            returnValue.append(new PathElementVisitor(){

                protected Object visitFieldPath(FieldPath fieldPath) {
                    return (index1 !=0?".":"") + fieldPath.field.getName();
                }

                protected Object visitAggreationPath(AggregationPath aggregationPath) {
                    return "_" + aggregationPath.getIndex();
                }

                protected Object visitPolymorphicPath(PolymorhicPath polymorhicPath) {
                    return ":" + polymorhicPath.actualType.getDiscriminator();
                }
            }.visit(pathElement));

            index++;
        }

        return returnValue.toString();
    }
}
